/*
	Copyright (c) 2011 Andrey O. Zbitnev (azbitnev@gmail.com)
	Licensed under the MIT License (LICENSE).

	$Id: ys.autocomplete.js 18 2012-04-13 05:39:54Z azbitnev@gmail.com $

	version: 0.3pa

	required modules: popup
*/

(function ($) {

	// private vars
	var serial = 1, contexts = { }

	// class popup
	$.ys.autocomplete = {

		create: function (selector, options) {

			var defaults = {
				caching: true,
				type: 'text', // items data type: text | html
				query: function (query, callback) {
					/*
					// example:
					callback([
						'Opt 1001',
						'Opt 1002',
						'Opt 1101',
						'Opt 1102',
						'Opt 1111',
						'Opt 1112'
					])
					*/
				},
				show: function ($list, $el) { $.ys.effects.showSlideDown($list) },
				hide: function ($list, $el) { $.ys.effects.hideSlideUp($list) }
			}

			var opts = $.extend(defaults, options);

			return $(selector).each(function () {

				var $el = $(this)
				var cache = { }

				$el.css({ display: 'none' })

				var html = ''
				+ '<div class="ys-autocomplete">'
					+ '<input type="text" class="' + this.className + '"/>' // TODO placeholder
					+ '<div class="ys-list"><div>'
						+ '<div class="top"></div>'
						+ '<div class="items"></div>'
						+ '<div class="bottom"></div>'
					+ '</div></div>'
				+ '</div>'

				var $ac = $(html).insertAfter($el), $list = $ac.find('.ys-list:eq(0)'), $field = $ac.find('input:eq(0)')

				if ($.browser.msie && $.browser.version <= 8) {
					$ac.addClass('ys-autocomplete-ie8')
					$list.addClass('ys-list-ie8')
				}

				if ($el.attr('disabled'))
					$field.attr('disabled', true)

				var dontHide = false

				$.ys.popup.create($ac, {
					show: opts.show,
					hide: opts.hide,
					popup: '.ys-list'
				})

				var popupCtx = $.ys.popup.getContext($ac)

				var ctx = {
					getElement: function () {
						return $el
					},
					query: function (query) {
						var items = []
						if (opts.caching)
							items = cache[query]
						function callback(items) {
							if (opts.caching)
								cache[query] = items
							ctx.setItems(items)
						}
						if (!items) {
							opts.query(query, callback)
							return
						} else {
							callback(items)
						}
					},
					setItems: function (items, hidden) {
						var $i = $list.find('.items:eq(0)')
						$i.children().remove()
						$.each(items, function (i, item) {
							var $item = $('<div class="item"/>')
							if (opts.type == 'text') {
								$item.text(item)
							} else if (opts.type == 'html') {
								$item.html(item)
							}
							$item.click(function (evt) {
								evt.stopPropagation()
								$i.children('.selected').removeClass('selected')
								$item.addClass('selected')
								$field.val(item)
								if (!dontHide)
									ctx.hide()
							})

							if ($.browser.msie && $.browser.version <= 8) {
								$item.hover(
									function () { $item.addClass('hovered') },
									function () { $item.removeClass('hovered') }
								)
							}

							$i.append($item)
						})
						if (!hidden)
							this.show()
					},
					show: function () {
						if ($list.find('input').attr('disabled'))
							return
						if ($list.css('visibility') == 'hidden')
							popupCtx.show()
					},
					hide: function () {
						if ($list.css('visibility') == 'visible')
							popupCtx.hide()
					}
				}

				var id = (serial ++)
				$el.data('ys-autocomplete-id', id)
				contexts[id] = ctx

				$field.bind(($.browser.msie && $.browser.version <= 8 ? 'propertychange' : 'input'), function (evt) {
					ctx.query($(this).val())
				}).keydown(function (evt) {
					switch(evt.keyCode) {
						case 27: // esc
							ctx.hide()
							return false
						break;
						case 40: // down
							var $s = $list.find('.selected')
							if ($s.length <= 0) {
								$s = $list.find('.item:eq(0)')
							} else {
								$s = $s.next('.item')
							}
							dontHide = true
							$s.click()
							dontHide = false
							return false
						break;
						case 38: // up
							var $s = $list.find('.selected')
							if ($s.length <= 0) {
								$s = $list.find('.item:last')
							} else {
								$s = $s.prev('.item')
							}
							dontHide = true
							$s.click()
							dontHide = false
							return false
						break;
						case 13: // enter
							ctx.hide()
						break;
					}
					return true
				})
			})
		},

		getContext: function (selector) {
			return contexts[$(selector).data('ys-popup-id')]
		}
	}

})(jQuery);

